/*****************************************************************************/
/*!	\file		PrintView.c
 *	\brief		C Source code file for the YX-PIS Example
 *	\par		Dalian Yunxing Tech Co., Ltd.
 *
 *				Dalian, China
 *				Phone   : +86 (411) 8825 4852
 *				Email   : yx@yunxing.tech
 */
/*****************************************************************************/

#include <stdlib.h>
#include <string.h>
#include "PrintView.h"
#include "LocalData.h"
#include "IEC61850API.h"

void PrintServerFullView()
{
	ClearScreen();
	PrintServerHeader();
	PrintDataView();
	PrintErrorString();
	PrintServerMenuView();
	printf("Select a Command: ");
	fflush(stdout); // Will now print everything in the stdout buffer
}

void PrintServerHeader()
{
	printf("----------------------------------------------------------------------------\n");
	printf("IEC61850 Server Example from yunxing.tech \nYX-PIS: %s\n", IEC61850_GetLibraryVersion());
	printf("----------------------------------------------------------------------------\n");
}

void PrintDataView()
{
	S8 i = 0; // Iterator variable for the loops

	printf("=================== IEC61850 Data ==========================================\n");
	printf("GGIO:\t SPCSO1.stVal: %s\t SPCSO2.stVal: %s\n", BooleanToString(GetGGIOStVal(1)), BooleanToString(GetGGIOStVal(2))); // Print GGIO Data
	printf("GGIO:\t SPCSO3.stVal: %s\t SPCSO4.stVal: %s\n", BooleanToString(GetGGIOStVal(3)), BooleanToString(GetGGIOStVal(4))); // Print GGIO Data
	printf("CSWI:\t Pos.stVal: %s\n", DBPosToString(GetCSWIStVal())); // Print CSWI Data
	printf("\n");

#ifdef __PARADIGM__
	/* Print MMXU Data */
	printf("MMXU:\t A.phsA.cVal.mag.i: %ld\t ", GetMMXUPhsAMagi());	// INT32 on beck is a long int so %ld is needed
	printf("A.phsB.cVal.mag.i: %ld\t ", GetMMXUPhsBMagi());
	printf("A.phsC.cVal.mag.i: %ld\n", GetMMXUPhsCMagi());
	printf("\n");

	/* We do not support floating point on BECK devices,
	 * thus, do not add floating point data for BECK.
	 */
#else
	/* Print MMXU Data */
	printf("MMXU:\t A.phsA.cVal.mag.i: %d\t ", GetMMXUPhsAMagi());
	printf("A.phsB.cVal.mag.i: %d\t ", GetMMXUPhsBMagi());
	printf("A.phsC.cVal.mag.i: %d\n", GetMMXUPhsCMagi());
	printf("\n");

	/* Print PDIF array element xVal */
	printf("PDIF:\t TmASt.crvPts xVal = { ");

	for (i = 0; i < SIZE_OF_PDIF_ARRAY - 1; i++) {
		printf("%2.2f, ", GetPDIFCrvPts(i).xVal);
	}
	printf("%3.2f }\n", GetPDIFCrvPts(SIZE_OF_PDIF_ARRAY - 1).xVal); // Print the last element in the array with the closing bracket and new line

	/* Print PDIF array element yVal */
	printf("PDIF:\t TmASt.crvPts yVal = { ");

	for (i = 0; i < SIZE_OF_PDIF_ARRAY - 1; i++) {
		printf("%3.2f, ", GetPDIFCrvPts(i).yVal);
	}
	printf("%2.2f }\n", GetPDIFCrvPts(SIZE_OF_PDIF_ARRAY - 1).yVal); // Print the last element in the array with the closing bracket and new line

	printf("\n");

	/* Print SV data */
	printf("TTNS:\t TnsSv1.instMag.f: %3.2f   ", GetTTNSTnsSv1Magf());
	printf("TnsSv2.instMag.f: %3.2f   ", GetTTNSTnsSv2Magf());
	printf("TnsSv3.instMag.f: %3.2f\n", GetTTNSTnsSv3Magf());
	printf("\n");

	/* Print SettingGroup data */
	printf("IARC:\t MaxNumRcd.setVal: %d   ", GetMaxNumRcd());
	printf("OpMod.setVal: %d   ", GetOpMod());
	printf("MemFull.setVal: %d\n", GetMemFull());
	printf("\n");
#endif
}

void PrintErrorString()
{
	printf("=================== Last Error =============================================\n");
	if (GetErrorString()[0] == 0) {
		printf("NONE\n");
	} else {
		printf("%s\n", GetErrorString());
	}
}

void PrintServerMenuView()
{
	printf("=================== IEC61850 Command Menu ==================================\n");
	printf("1) Update A.phsA.cVal.mag.i \t DAID: {3,0,0,0,0}\n");
	printf("2) Update A.phsB.cVal.mag.i \t DAID: {4,0,0,0,0}\n");
	printf("3) Update A.phsC.cVal.mag.i \t DAID: {5,0,0,0,0}\n");

	/* We do not support floating point on BECK devices,
	 * thus, do not add floating point data for BECK.
	 */
#ifndef __PARADIGM__
	printf("4) Update TmASt.crvPts(i).xVal \t DAID: {6,0,0,0,0} \n");
	printf("5) Update TmASt.crvPts(i).yVal\n");
	printf("6) Update TnsSv1.instMag.f \t DAID: {7,0,0,0,0}\n");
	printf("7) Update TnsSv2.instMag.f \t DAID: {7,0,0,0,1}\n");
	printf("8) Update TnsSv3.instMag.f \t DAID: {7,0,0,0,2}\n");
#endif
	printf("X) To Exit\n");
	printf("============================================================================\n");
}

void PrintClientFullView()
{
	ClearScreen();
	PrintClientHeader();
	PrintDataView();
	PrintErrorString();
	PrintClientMenuView();
	printf("Select a Command: ");
	fflush(stdout); // Will now print everything in the stdout buffer
}

void PrintClientHeader()
{
	printf("----------------------------------------------------------------------------\n");
	printf("IEC61850 Client Example from yunxing.tech \nYX-PIS: %s\n", IEC61850_GetLibraryVersion());
	printf("----------------------------------------------------------------------------\n");
}

void PrintClientMenuView()
{
	printf("=================== IEC61850 Command Menu ==================================\n");
	printf("0) Get Connected Server List\n");
	printf("1) Report Menu\n");
	printf("2) Control Menu\n");
	printf("3) File Menu\n");
	printf("4) Log Menu\n");
	printf("5) Setting Group Menu\n");
	printf("6) Data Access Menu \n");
	printf("X) To Exit\n");
	printf("============================================================================\n");
}

void PrintReportMenuView()
{
	printf("================ Report Menu ================\n");
	printf("1) GetBRCBValues\n");
	printf("2) SetBRCBValues\n");
	printf("3) GetURCBValues\n");
	printf("4) SetURCBValues\n");
	printf("0) Return to main menu\n");
}

void PrintControlMenuView()
{
	printf("================ Control Menu ================\n");
	printf("1) Direct-with-normal-security   GGIO SPCSO1 DAID: {2,0,0,0,1}\n");
	printf("2) Sbo-with-normal-security      GGIO SPCSO2 DAID: {2,0,0,0,2}\n");
	printf("3) Direct-with-enhanced-security GGIO SPCSO3 DAID: {2,0,0,0,3}\n");
	printf("4) Sbo-with-enhanced-security    GGIO SPCSO4 DAID: {2,0,0,0,4}\n");
	printf("5) Sbo-with-enhanced-security    CSWI Pos    DAID: {1,0,0,0,0}\n");
	printf("0) Return to main menu\n");
}

void PrintFileMenuView()
{
	printf("================ File Menu ================\n");
	printf("1) GetFile\n");
	printf("2) SetFile\n");
	printf("3) DeleteFile\n");
	printf("4) GetFileAttributeValues\n");
	printf("0) Return to main menu\n");
}

void PrintLogMenuView()
{
	printf("================ Log Menu ================\n");
	printf("1) QueryLogByTime\n");
	printf("2) QueryLogAfter\n");
	printf("3) GetLogStatusValues\n");
	printf("0) Return to main menu\n");
}

void PrintSettingGroupMenuView()
{
	printf("================ SettingGroup Menu ================\n");
	printf("1) GetEditSGValue\n");
	printf("2) SelectActiveSG\n");
	printf("3) SelectEditSG\n");
	printf("4) SetEditSGValue\n");
	printf("5) ConfirmEditSGValues\n");
	printf("6) GetSGCBValues\n");
	printf("0) Return to main menu\n");
}

void PrintDataAccessMenuView()
{
	printf("================ Data Access Menu ================\n");
	printf("1) GetServerDirectory\n");
	printf("2) GetLogicalDeviceDirectory\n");
	printf("3) GetLogicalNodeDirectory\n");
	printf("4) GetAllDataValues\n");
	printf("5) GetAllCBValues\n");
	printf("6) GetDataValues\n");
	printf("7) SetDataValues\n");
	printf("8) GetDataDirectory\n");
	printf("9) GetDataDefinition\n");
	printf("10) GetDataSetValues\n");
	printf("11) SetDataSetValues\n");
	printf("12) CreateDataSet\n");
	printf("13) DeleteDataSet\n");
	printf("14) GetDataSetDirectory\n");
	printf("0) Return to main menu\n");
}

void PrintServerSubscriptionFullView()
{
	ClearScreen();
	PrintServerSubscriptionHeader();
	PrintServerSubscriptionDataView();
	PrintErrorString();
	PrintServerSubscriptionMenuView();
	printf("Select a Command: ");
	fflush(stdout); // Will now print everything in the stdout buffer
}

void PrintServerSubscriptionHeader()
{
	printf("----------------------------------------------------------------------------\n");
	printf("IEC61850 Server Subscription Example from yunxing.tech \nYX-PIS: %s\n", IEC61850_GetLibraryVersion());
	printf("----------------------------------------------------------------------------\n");
}

void PrintServerSubscriptionDataView()
{
	printf("=================== IEC61850 Data ==========================================\n");

	printf("CSWI:\t stVal: %s\n", DBPosToString(GetCSWIStVal())); // Print CSWI Data
	printf("GGIO:\t stVal: %s\n", BooleanToString(GetGGIOStVal(1))); // Print GGIO Data
	printf("\n");
}

void PrintServerSubscriptionMenuView()
{
	printf("=================== IEC61850 Command Menu ==================================\n");
	printf("X) To Exit\n");
	printf("============================================================================\n");
}

const char* BooleanToString(Boolean inBool)
{
	const char* returnString;
	static const char* const boolStrings[] = { "True", "False" };

	if (inBool == FALSE) {
		returnString = boolStrings[1]; //Set returnString to False
	} else {
		returnString = boolStrings[0]; //Set returnString to True
	}

	return returnString;
}

const char* DBPosToString(eDbPosValues inDBPosVal)
{
	const char* returnString;
	static const char* const dbPosStrings[] = { "INTERMEDIATE", "OFF", "ON", "BAD" };

	switch (inDBPosVal) {
	case DBPOS_INTERMEDIATE:
		returnString = dbPosStrings[0];
		break;
	case DBPOS_OFF:
		returnString = dbPosStrings[1];
		break;
	case DBPOS_ON:
		returnString = dbPosStrings[2];
		break;
	case DBPOS_BAD:
		returnString = dbPosStrings[3];
		break;
	default:
		returnString = NULL;
		break;
	}

	return returnString;
}

void ClearScreen()
{
	/* There is no CLS or clear command on beck RTOS so only execute if this is not a BECK Device*/
#ifndef __PARADIGM__
	if (system("CLS")) { system("clear"); }
#else
	printf("\n\n\n\n\n\n\n\n\n\n");	// on Beck just push the old screen up by 10 lines
#endif

#ifndef WIN32
	printf("\033[2J\033[1;1H");	// Clear Screen ANSI (not supported on windows)
#endif
}

void PrintStringList(StringList* list)
{
	if (list) {
		unsigned int index = 0;
		for (index = 0; index < list->length; index++) {
			printf("\t%d.%s\n", index + 1, list->list[index]);
		}
	}
}

void PrintServiceError(eServiceError error)
{
	printf("ServiceError: (%d) %s\n", error, TranslateServiceError(error));
}

void PrintMoreFollows(Boolean moreFollows)
{
	if (moreFollows) {
		printf("MoreFollows = TRUE\n");
	} else {
		printf("MoreFollows = FALSE\n");
	}
}

void PrintTimeStamp(IEC61850_TimeStamp* timeStamp)
{
	if (timeStamp) {
		IEC61850_DateTime T = { 0 };
		IEC61850_GetDateFromIEC61850Time(&T, timeStamp);

		printf("[%d/%02d/%02d %02d:%02d:%02d.%d]", T.year, T.month, T.tm_mday, T.tm_hour, T.tm_min, T.tm_sec, T.tm_uSec);
	}
}

void PrintQuality(void* quality, unsigned int printLevel, Boolean bDetailed)
{
	if (quality == NULL) {
		unsigned int i = 0;
		for (i = 0; i < printLevel; i++) { printf("  "); }
		printf("NULL\n");
	} else {
		tIEC61850Quality q;
		char* sValidity = "good";

		memcpy(&q, quality, sizeof(tIEC61850Quality));
		switch (q & IEC61850_QUALITY_BITMASK_VALIDITY) {
		case IEC61850_QUALITY_GOOD:
			sValidity = "good";
			break;
		case IEC61850_QUALITY_INVALID:
			sValidity = "invalid";
			break;
		case IEC61850_QUALITY_RESERVED:
			sValidity = "reserved";
			break;
		case IEC61850_QUALITY_QUESTIONABLE:
			sValidity = "questionable";
			break;
		}
		printf("[%s]\n", sValidity);
	}
	return;
}

void PrintBRCBValues(BRCBValues* brcbVal)
{
	if (brcbVal) {
		int i = 0;
		printf("(BRCB)\n\n");
		printf("\trptID:    [%s]\n", brcbVal->rptId);
		printf("\trptEna:   [%s]\n", brcbVal->rptEna ? "TRUE" : "FALSE");
		printf("\tdatSet:   [%s]\n", brcbVal->datSet);
		printf("\tconfRev:  [%u]\n", brcbVal->confRev);
		printf("\toptFlds:\n");
		printf("\t  reserved:             [-]\n");
		printf("\t  sequence-number:      [%s]\n", (brcbVal->optFlds & IEC61850_REPORT_OPTIONAL_SEQUENCE_NUMBER) ? "TRUE" : "FALSE");
		printf("\t  report-time-stamp:    [%s]\n", (brcbVal->optFlds & IEC61850_REPORT_OPTIONAL_REPORT_TIME_STAMP) ? "TRUE" : "FALSE");
		printf("\t  reason-for-inclusion: [%s]\n", (brcbVal->optFlds & IEC61850_REPORT_OPTIONAL_REASON_FOR_INCLUSION) ? "TRUE" : "FALSE");
		printf("\t  data-set-name:        [%s]\n", (brcbVal->optFlds & IEC61850_REPORT_OPTIONAL_DATA_SET_NAME) ? "TRUE" : "FALSE");
		printf("\t  data-reference:       [%s]\n", (brcbVal->optFlds & IEC61850_REPORT_OPTIONAL_DATA_REFERENCE) ? "TRUE" : "FALSE");
		printf("\t  buffer-overflow:      [%s]\n", (brcbVal->optFlds & IEC61850_REPORT_OPTIONAL_BUFFER_OVERFLOW) ? "TRUE" : "FALSE");
		printf("\t  entryId:              [%s]\n", (brcbVal->optFlds & IEC61850_REPORT_OPTIONAL_ENTRY_ID) ? "TRUE" : "FALSE");
		printf("\t  conf-revision:        [%s]\n", (brcbVal->optFlds & IEC61850_REPORT_OPTIONAL_CONF_REVISION) ? "TRUE" : "FALSE");
		printf("\t  segmentation:         [%s]\n", (brcbVal->optFlds & IEC61850_REPORT_OPTIONAL_SEGMENTATION) ? "TRUE" : "FALSE");
		printf("\tbufTm:    [%u]\n", brcbVal->bufTm);
		printf("\tsqNum:    [%u]\n", brcbVal->sqNum);
		printf("\ttrgOps:\n");
		printf("\t  reserved:              [-]\n");
		printf("\t  data-change:           [%s]\n", (brcbVal->trgOps & IEC61850_TRIGGER_OPTIONS_DATA_CHANGE) ? "TRUE" : "FALSE");
		printf("\t  quality-change:        [%s]\n", (brcbVal->trgOps & IEC61850_TRIGGER_OPTIONS_QUATLITY_CHANGE) ? "TRUE" : "FALSE");
		printf("\t  data-update:           [%s]\n", (brcbVal->trgOps & IEC61850_TRIGGER_OPTIONS_DATA_UPDATE) ? "TRUE" : "FALSE");
		printf("\t  integrity:             [%s]\n", (brcbVal->trgOps & IEC61850_TRIGGER_OPTIONS_INTEGRITY) ? "TRUE" : "FALSE");
		printf("\t  general-interrogation: [%s]\n", (brcbVal->trgOps & IEC61850_TRIGGER_OPTIONS_GI) ? "TRUE" : "FALSE");
		printf("\tintgPd:   [%u]\n", brcbVal->intgPd);
		printf("\tgi:       [%s]\n", brcbVal->gi ? "TRUE" : "FALSE");
		printf("\tpurgeBuf: [%s]\n", brcbVal->purgeBuf ? "TRUE" : "FALSE");
		printf("\tentryID:  [");
		for (i = 0; i < 8; i++) {
			printf("%02X", brcbVal->entryId[i]);
		}
		printf("] (HEX)\n");
		printf("\tresvTms:  [%u]\n", brcbVal->resvTms);
		if (brcbVal->owner[0] == 0) {
			printf("\towner:    [""]\n");
		} else {
			printf("\towner:    [%d.%d.%d.%d]\n", brcbVal->owner[0], brcbVal->owner[1], brcbVal->owner[2], brcbVal->owner[3]);
		}

		printf("\n");
	}
}

void PrintURCBValues(URCBValues* urcbVal)
{
	if (urcbVal) {
		printf("(URCB)\n");
		printf("\trptID:    [%s]\n", urcbVal->rptId);
		printf("\trptEna:   [%s]\n", urcbVal->rptEna ? "TRUE" : "FALSE");
		printf("\tdatSet:   [%s]\n", urcbVal->datSet);
		printf("\tconfRev:  [%u]\n", urcbVal->confRev);
		printf("\toptFlds:\n");
		printf("\t  reserved:             [-]\n");
		printf("\t  sequence-number:      [%s]\n", (urcbVal->optFlds & IEC61850_REPORT_OPTIONAL_SEQUENCE_NUMBER) ? "TRUE" : "FALSE");
		printf("\t  report-time-stamp:    [%s]\n", (urcbVal->optFlds & IEC61850_REPORT_OPTIONAL_REPORT_TIME_STAMP) ? "TRUE" : "FALSE");
		printf("\t  reason-for-inclusion: [%s]\n", (urcbVal->optFlds & IEC61850_REPORT_OPTIONAL_REASON_FOR_INCLUSION) ? "TRUE" : "FALSE");
		printf("\t  data-set-name:        [%s]\n", (urcbVal->optFlds & IEC61850_REPORT_OPTIONAL_DATA_SET_NAME) ? "TRUE" : "FALSE");
		printf("\t  data-reference:       [%s]\n", (urcbVal->optFlds & IEC61850_REPORT_OPTIONAL_DATA_REFERENCE) ? "TRUE" : "FALSE");
		printf("\t  buffer-overflow:      [%s]\n", (urcbVal->optFlds & IEC61850_REPORT_OPTIONAL_BUFFER_OVERFLOW) ? "TRUE" : "FALSE");
		printf("\t  entryId:              [%s]\n", (urcbVal->optFlds & IEC61850_REPORT_OPTIONAL_ENTRY_ID) ? "TRUE" : "FALSE");
		printf("\t  conf-revision:        [%s]\n", (urcbVal->optFlds & IEC61850_REPORT_OPTIONAL_CONF_REVISION) ? "TRUE" : "FALSE");
		printf("\t  segmentation:         [%s]\n", (urcbVal->optFlds & IEC61850_REPORT_OPTIONAL_SEGMENTATION) ? "TRUE" : "FALSE");
		printf("\tbufTm:    [%u]\n", urcbVal->bufTm);
		printf("\tsqNum:    [%u]\n", urcbVal->sqNum);
		printf("\ttrgOps:\n");
		printf("\t  reserved:              [-]\n");
		printf("\t  data-change:           [%s]\n", (urcbVal->trgOps & IEC61850_TRIGGER_OPTIONS_DATA_CHANGE) ? "TRUE" : "FALSE");
		printf("\t  quality-change:        [%s]\n", (urcbVal->trgOps & IEC61850_TRIGGER_OPTIONS_QUATLITY_CHANGE) ? "TRUE" : "FALSE");
		printf("\t  data-update:           [%s]\n", (urcbVal->trgOps & IEC61850_TRIGGER_OPTIONS_DATA_UPDATE) ? "TRUE" : "FALSE");
		printf("\t  integrity:             [%s]\n", (urcbVal->trgOps & IEC61850_TRIGGER_OPTIONS_INTEGRITY) ? "TRUE" : "FALSE");
		printf("\t  general-interrogation: [%s]\n", (urcbVal->trgOps & IEC61850_TRIGGER_OPTIONS_GI) ? "TRUE" : "FALSE");
		printf("\tintgPd:   [%u]\n", urcbVal->intgPd);
		printf("\tgi:       [%s]\n", urcbVal->gi ? "TRUE" : "FALSE");
		printf("\tresv:	  [%s]\n", urcbVal->resv ? "TRUE" : "FALSE");
		if (urcbVal->owner[0] == 0) {
			printf("\towner:    [""]\n");
		} else {
			printf("\towner:    [%d.%d.%d.%d]\n", urcbVal->owner[0], urcbVal->owner[1], urcbVal->owner[2], urcbVal->owner[3]);
		}

		printf("\n");
	}
}

void PrintRCBValues(RCBValues* rcbValues, Boolean buffFlag)
{
	if (rcbValues) {
		printf(buffFlag ? "(BRCB)\n" : "(URCB)\n");
		printf("\trptID:    [%s]\n", rcbValues->rptId);
		printf("\trptEna:   [%s]\n", rcbValues->rptEna ? "TRUE" : "FALSE");
		printf("\tdatSet:   [%s]\n", rcbValues->datSet);
		printf("\tconfRev:  [%u]\n", rcbValues->confRev);
		printf("\toptFlds:\n");
		printf("\t  reserved:             [-]\n");
		printf("\t  sequence-number:      [%s]\n", (rcbValues->optFlds & IEC61850_REPORT_OPTIONAL_SEQUENCE_NUMBER) ? "TRUE" : "FALSE");
		printf("\t  report-time-stamp:    [%s]\n", (rcbValues->optFlds & IEC61850_REPORT_OPTIONAL_REPORT_TIME_STAMP) ? "TRUE" : "FALSE");
		printf("\t  reason-for-inclusion: [%s]\n", (rcbValues->optFlds & IEC61850_REPORT_OPTIONAL_REASON_FOR_INCLUSION) ? "TRUE" : "FALSE");
		printf("\t  data-set-name:        [%s]\n", (rcbValues->optFlds & IEC61850_REPORT_OPTIONAL_DATA_SET_NAME) ? "TRUE" : "FALSE");
		printf("\t  data-reference:       [%s]\n", (rcbValues->optFlds & IEC61850_REPORT_OPTIONAL_DATA_REFERENCE) ? "TRUE" : "FALSE");
		printf("\t  buffer-overflow:      [%s]\n", (rcbValues->optFlds & IEC61850_REPORT_OPTIONAL_BUFFER_OVERFLOW) ? "TRUE" : "FALSE");
		printf("\t  entryId:              [%s]\n", (rcbValues->optFlds & IEC61850_REPORT_OPTIONAL_ENTRY_ID) ? "TRUE" : "FALSE");
		printf("\t  conf-revision:        [%s]\n", (rcbValues->optFlds & IEC61850_REPORT_OPTIONAL_CONF_REVISION) ? "TRUE" : "FALSE");
		printf("\t  segmentation:         [%s]\n", (rcbValues->optFlds & IEC61850_REPORT_OPTIONAL_SEGMENTATION) ? "TRUE" : "FALSE");
		printf("\tbufTm:    [%u]\n", rcbValues->bufTm);
		printf("\tsqNum:    [%u]\n", rcbValues->sqNum);
		printf("\ttrgOps:\n");
		printf("\t  reserved:              [-]\n");
		printf("\t  data-change:           [%s]\n", (rcbValues->trgOps & IEC61850_TRIGGER_OPTIONS_DATA_CHANGE) ? "TRUE" : "FALSE");
		printf("\t  quality-change:        [%s]\n", (rcbValues->trgOps & IEC61850_TRIGGER_OPTIONS_QUATLITY_CHANGE) ? "TRUE" : "FALSE");
		printf("\t  data-update:           [%s]\n", (rcbValues->trgOps & IEC61850_TRIGGER_OPTIONS_DATA_UPDATE) ? "TRUE" : "FALSE");
		printf("\t  integrity:             [%s]\n", (rcbValues->trgOps & IEC61850_TRIGGER_OPTIONS_INTEGRITY) ? "TRUE" : "FALSE");
		printf("\t  general-interrogation: [%s]\n", (rcbValues->trgOps & IEC61850_TRIGGER_OPTIONS_GI) ? "TRUE" : "FALSE");
		printf("\tintgPd:   [%u]\n", rcbValues->intgPd);
		printf("\tgi:       [%s]\n", rcbValues->gi ? "TRUE" : "FALSE");

		if (buffFlag) {
			int i = 0;
			printf("\tpurgeBuf: [%s]\n", rcbValues->purgeBuf ? "TRUE" : "FALSE");
			printf("\tentryID:  [");
			for (i = 0; i < 8; i++) {
				printf("%02X", rcbValues->entryId[i]);
			}
			printf("] (HEX)\n");
			printf("\tresvTms:  [%u]\n", rcbValues->resvTms);
		} else {
			printf("\tresv:     [%s]\n", rcbValues->resv ? "TRUE" : "FALSE");
		}

		if (rcbValues->owner[0] == 0) {
			printf("\towner:    [""]\n");
		} else {
			printf("\towner:    [%d.%d.%d.%d]\n", rcbValues->owner[0], rcbValues->owner[1], rcbValues->owner[2], rcbValues->owner[3]);
		}

		printf("\n");
	}
}

void PrintLogCBVals(LCBValues* lcbValues)
{
	if (lcbValues) {
		printf("(LCB)\n");
		printf("\tlogEna:  [%s]\n", lcbValues->logEna ? "TRUE" : "FALSE");
		printf("\tdataSet: [%s]\n", lcbValues->datSet);
		printf("\ttrgOps:\n");
		printf("\t  reserved:              [-]\n");
		//printf("\t  reserved:              [%s]\n", (lcbValues->trgOps & 0x80) ? "TRUE" : "FALSE");
		printf("\t  data-change:           [%s]\n", (lcbValues->trgOps & 0x40) ? "TRUE" : "FALSE");
		printf("\t  data-update:           [%s]\n", (lcbValues->trgOps & 0x20) ? "TRUE" : "FALSE");
		printf("\t  quality-change:        [%s]\n", (lcbValues->trgOps & 0x10) ? "TRUE" : "FALSE");
		printf("\t  integrity:             [%s]\n", (lcbValues->trgOps & 0x08) ? "TRUE" : "FALSE");
		printf("\t  general-interrogation: [%s]\n", (lcbValues->trgOps & 0x04) ? "TRUE" : "FALSE");
		printf("\tintgPd:  [%u]\n", lcbValues->intgPd);
		printf("\tlogRef:  [%s]\n", lcbValues->logRef);
		printf("\toptFlds:\n");
		printf("\t  reason-for-inclusion: [%s]\n", (*(Boolean*)(&lcbValues->optFlds)) ? "TRUE" : "FALSE");
		printf("\tbufTm:   [%u]\n", lcbValues->bufTm);
		printf("\n");
	}
}

void PrintGoCBVals(GoCBValues* cbValues)
{
	if (cbValues) {
		printf("(GoCB)\n");
		printf("\tgoEna:   [%s]\n", cbValues->goEna ? "TRUE" : "FALSE");
		printf("\tgoID:    [%s]\n", cbValues->goID);
		printf("\tdatSet:  [%s]\n", cbValues->datSet);
		printf("\tconfRev: [%u]\n", cbValues->confRev);
		printf("\tndsCom:  [%s]\n", cbValues->ndsCom ? "TRUE" : "FALSE");
		printf("\tdstAddress:\n");
		printf("\t  addr:     [%02X-%02X-%02X-%02X-%02X-%02X]\n", cbValues->addr[0], cbValues->addr[1], cbValues->addr[2], cbValues->addr[3], cbValues->addr[4], cbValues->addr[5]);
		printf("\t  priority: [%u]\n", cbValues->priority);
		printf("\t  vid:      [%03u]\n", cbValues->vid);
		printf("\t  appid:    [%04X]\n", cbValues->appid);
		printf("\n");
	}
}

void PrintMSVCBVals(MSVCBValues* cbValues)
{
	if (cbValues) {
		printf("(MSVCB)\n");
		printf("\tsvEna:   [%s]\n", cbValues->svEna ? "TRUE" : "FALSE");
		printf("\tmsvID:   [%s]\n", cbValues->msvID);
		printf("\tdatSet:  [%s]\n", cbValues->datSet);
		printf("\tconfRev: [%u]\n", cbValues->confRev);
		printf("\tsmpMod:  [%d] %s\n", (SampleMode)cbValues->smpMod, TranslateSampleMode((SampleMode)cbValues->smpMod));
		printf("\tsmpRate: [%u]\n", cbValues->smpRate);
		printf("\toptFlds:\n");
		printf("\t  refresh-time:  [%s]\n", (cbValues->optFlds & 0x80) ? "TRUE" : "FALSE");
		printf("\t  reserved:      [-]\n");
		printf("\t  sample-rate:   [%s]\n", (cbValues->optFlds & 0x20) ? "TRUE" : "FALSE");
		printf("\t  data-set-name: [%s]\n", (cbValues->optFlds & 0x10) ? "TRUE" : "FALSE");
		printf("\t  security:      [%s]\n", (cbValues->optFlds & 0x08) ? "TRUE" : "FALSE");
		printf("\tdstAddress:\n");
		printf("\t  addr:     [%02X-%02X-%02X-%02X-%02X-%02X]\n", cbValues->addr[0], cbValues->addr[1], cbValues->addr[2], cbValues->addr[3], cbValues->addr[4], cbValues->addr[5]);
		printf("\t  priority: [%u]\n", cbValues->priority);
		printf("\t  vid:      [%03u]\n", cbValues->vid);
		printf("\t  appid:    [%04X]\n", cbValues->appid);
		printf("\n");
	}
}

void PrintSGCBVals(SGCBValues* sgcbValues)
{
	if (sgcbValues) {
		IEC61850_DateTime dateTime = { 0 };
		IEC61850_GetDateFromIEC61850Time(&dateTime, &sgcbValues->lActTm);

		printf("(SGCB)\n");
		printf("\tnumOfSG: [%u]\n", sgcbValues->numOfSG);
		printf("\tactSG:   [%u]\n", sgcbValues->actSG);
		printf("\teditSG:  [%u]\n", sgcbValues->editSG);
		printf("\tlActTm:  ");
		PrintTimeStamp(&sgcbValues->lActTm);
		printf("\tresvTms: [%u]\n", sgcbValues->resvTms);
		printf("\n");
	}
}

void PrintAllCBValues(GetAllCBValsReturn* allCBVals)
{
	unsigned int index = 0;

	for (index = 0; index < allCBVals->numOfCB; index++) {
		if (allCBVals->brcbValues) {
			PrintRCBValues(&allCBVals->brcbValues[index], TRUE);
		}
		if (allCBVals->urcbValues) {
			PrintRCBValues(&allCBVals->urcbValues[index], FALSE);
		}
		if (allCBVals->sgcbValues) {
			PrintSGCBVals(&allCBVals->sgcbValues[index]);
		}
		if (allCBVals->lcbValues) {
			PrintLogCBVals(&allCBVals->lcbValues[index]);
		}
		if (allCBVals->goCBValues) {
			PrintGoCBVals(&allCBVals->goCBValues[index]);
		}
		if (allCBVals->svCBValues) {
			PrintMSVCBVals(&allCBVals->svCBValues[index]);
		}
	}
}

void PrintLogVals(IEC61850_LogEntries* logEntries)
{
	if (logEntries == NULL) {
		printf("Log Val list Error\n");
	} else {
		U64 entryId = 0;
		unsigned int i = 0;
		unsigned int j = 0;
		for (i = 0; i < logEntries->numOfEntries; i++) {
			printf("No. %d:\n", i + 1);
			entryId = (U64)logEntries->entries[i].entryId[0] * 0x100000000000000
				+ (U64)logEntries->entries[i].entryId[1] * 0x1000000000000
				+ (U64)logEntries->entries[i].entryId[2] * 0x10000000000
				+ (U64)logEntries->entries[i].entryId[3] * 0x100000000
				+ (U64)logEntries->entries[i].entryId[4] * 0x1000000
				+ (U64)logEntries->entries[i].entryId[5] * 0x10000
				+ (U64)logEntries->entries[i].entryId[6] * 0x100
				+ logEntries->entries[i].entryId[7];
			printf("  EntryID:       [%llu]\n", entryId);
			printf("  TimeOfEntry:   ");
			PrintTimeStamp(&logEntries->entries[i].entryTime);
			printf("\n  EntryData:\n");
			for (j = 0; j < logEntries->entries[i].numOfLogEntryData; j++) {
				IEC61850_ReasonCode reasonCode;
				printf("\tDataRef: [%s] (FC=%s)\n", logEntries->entries[i].logEntryData[j].DataRef, logEntries->entries[i].logEntryData[j].FC);
				printf("\tValue:\n");
				PrintDAVal(&logEntries->entries[i].logEntryData[j].logValue, 6);
				reasonCode = logEntries->entries[i].logEntryData[j].reasonCode;
				printf("\tReasonCode:\n");
				if (reasonCode & IEC61850_DATA_CHANGE) {
					printf("\t  [data-change]\n");
				}
				if (reasonCode & IEC61850_QUALITY_CHANGE) {
					printf("\t  [quality-change]\n");
				}
				if (reasonCode & IEC61850_DATA_UPDATE) {
					printf("\t  [data-update]\n");
				}
				if (reasonCode & IEC61850_INTEGRITY) {
					printf("\t  [integrity]\n");
				}
				if (reasonCode & IEC61850_APPLICATION_TRIGGER) {
					printf("\t  [application-trigger]\n");
				}
			}
		}

		if (logEntries->moreFollows) {
			printf("More Follows\n");
		}
	}
}

void PrintLogStatus(IEC61850_LogStatus* logStatus)
{
	if (logStatus) {
		printf("\tOldestEntryTime:");
		PrintTimeStamp(&logStatus->OldestEntryTime);
		printf("\n\tNewestEntryTime:");
		PrintTimeStamp(&logStatus->NewestEntryTime);
		printf("\n\tOldestEntry:%llu\n", logStatus->OldestEntry);
		printf("\tNewestEntry:%llu\n", logStatus->NewestEntry);
	}
}

void PrintDAVal(IEC61850_DataAttributeData* dataAttribute, int level)
{
	if (dataAttribute) {
		char formatSpace[256] = { 0 };
		int i = 0;
		for (i = 0; i < level; i++) {
			strcat(formatSpace, "  ");
		}
		if (dataAttribute->pvData) {
			switch (dataAttribute->type) {
			case IEC61850_DATATYPE_BOOLEAN:
				if (*((Boolean*)dataAttribute->pvData)) {
					printf("%sBOOLEAN:TRUE\n", formatSpace);
				} else {
					printf("%sBOOLEAN:FALSE\n", formatSpace);
				}
				break;
			case IEC61850_DATATYPE_INT8:
				printf("%sINT8:%d\n", formatSpace, *((S8*)dataAttribute->pvData));
				break;
			case IEC61850_DATATYPE_INT8U:
				printf("%sINT8U:%d\n", formatSpace, *((U8*)dataAttribute->pvData));
				break;
			case IEC61850_DATATYPE_INT16:
				printf("%sINT16:%d\n", formatSpace, *((S16*)dataAttribute->pvData));
				break;
			case IEC61850_DATATYPE_INT16U:
				printf("%sINT16U:%u\n", formatSpace, *((U16*)dataAttribute->pvData));
				break;
			case IEC61850_DATATYPE_INT32:
				printf("%sINT32:%d\n", formatSpace, *((S32*)dataAttribute->pvData));
				break;
			case IEC61850_DATATYPE_INT32U:
				printf("%sINT32U:%u\n", formatSpace, *((U32*)dataAttribute->pvData));
				break;
			case IEC61850_DATATYPE_INT64:
				printf("%sINT64:%lld\n", formatSpace, *((S64*)dataAttribute->pvData));
				break;
			case IEC61850_DATATYPE_FLOAT32:
				printf("%sFLOAT32:%f\n", formatSpace, *((Float32*)dataAttribute->pvData));
				break;
			case IEC61850_DATATYPE_FLOAT64:
				printf("%sFLOAT64:%f\n", formatSpace, *((Float64*)dataAttribute->pvData));
				break;
			case IEC61850_DATATYPE_VISIBLE_STRING:
				printf("%sVISIBLE_STRING:%s\n", formatSpace, ((char*)dataAttribute->pvData));
				break;
			case IEC61850_DATATYPE_TIMESTAMP:
			{
				printf("%s%s", formatSpace, "TIMESTAMP:");
				PrintTimeStamp((IEC61850_TimeStamp*)dataAttribute->pvData);
				printf("\n");
				break;
			}
			case IEC61850_DATATYPE_UNICODE_STRING:
			case IEC61850_DATATYPE_OCTET_STRING:
			{
				unsigned int index = 0;
				if (dataAttribute->type == IEC61850_DATATYPE_UNICODE_STRING) {
					printf("%sUNICODE_STRING:", formatSpace);
				} else {
					printf("%sOCTET_STRING:", formatSpace);
				}
				while (index < ((dataAttribute->bitLength + 7) / 8)) {
					printf("%02X", ((unsigned char*)dataAttribute->pvData)[index]);
					index++;
				}
				printf("\n");
				break;
			}
			case IEC61850_DATATYPE_QUALITY:
			case IEC61850_DATATYPE_CODED_ENUM:
			case IEC61850_DATATYPE_ENUMERATED:
			{
				char* bitString = (char*)calloc(dataAttribute->bitLength + 1, sizeof(char));
				if (bitString) {
					unsigned int byteSize = (dataAttribute->bitLength + 7) / 8;
					unsigned int count = 0;
					unsigned int byteIndex = 0;
					unsigned int bitIndex = 0;
					char* data = (char*)(dataAttribute->pvData);
					for (byteIndex = 0; byteIndex < byteSize && count < dataAttribute->bitLength; byteIndex++) {
						for (bitIndex = 0; bitIndex < 8 && count < dataAttribute->bitLength; bitIndex++) {
							bitString[count] = data[byteIndex] << bitIndex;
							if (0x80 & bitString[count]) {
								bitString[count] = '1';
							} else {
								bitString[count] = '0';
							}
							count++;
						}
					}
					if (dataAttribute->type == IEC61850_DATATYPE_QUALITY) {
						printf("%sQUALITY:%s\n", formatSpace, bitString);
					} else if (dataAttribute->type == IEC61850_DATATYPE_CODED_ENUM) {
						printf("%sCODED_ENUM:%s\n", formatSpace, bitString);
					} else {
						printf("%sENUMERATED:%s\n", formatSpace, bitString);
					}

					free(bitString);
				}
				break;
			}
			case IEC61850_DATATYPE_ARRAY:
			case IEC61850_DATATYPE_STRUCTURE:
			{
				unsigned int index = 0;
				if (dataAttribute->type == IEC61850_DATATYPE_ARRAY) {
					printf("%sArray:%u\n", formatSpace, dataAttribute->bitLength);
				} else {
					printf("%sStruct:%u\n", formatSpace, dataAttribute->bitLength);
				}
				for (index = 0; index < dataAttribute->bitLength; index++) {
					PrintDAVal(&((IEC61850_DataAttributeData*)dataAttribute->pvData)[index], level + 1);
				}
			}
			}
		}
	}
}

void PrintDataType(unsigned int dataType, unsigned int bitLength, unsigned int printLevel)
{
	char* sDataType[20] = { "ERROR","BOOLEAN","INT8","INT16","INT32","INT64","INT8U","INT16U",
		"INT32U","FLOAT32","FLOAT64","ENUMERATED","CODED_ENUM","OCTET_STRING","VISIBLE_STRING",
		"UNICODE_STRING","TIMESTAMP","QUALITY","ARRAY","STRUCTURE" };
	unsigned int i = 0;
	for (i = 0; i < printLevel; i++) { printf("  "); }

	printf("type: ");

	if (dataType >= 0 && dataType < 20) {
		if (dataType == 3 || dataType == 4 || dataType == 5) {
			switch (bitLength) {
			case 8:
				printf("[INT8]\n");
				break;
			case 16:
				printf("[INT16]\n");
				break;
			case 32:
				printf("[INT32]\n");
				break;
			case 64:
				printf("[INT64]\n");
				break;
			}
		} else if (dataType == 7 || dataType == 8) {
			switch (bitLength) {
			case 8:
				printf("[INT8U]\n");
				break;
			case 16:
				printf("[INT16U]\n");
				break;
			case 32:
				printf("[INT32U]\n");
				break;
			}
		} else {
			printf("[%s]\n", sDataType[dataType]);
		}
	} else {
		printf("[(invalid)]\n");
	}
	return;
}

void PrintDataValue(const IEC61850_DataAttributeData* value, unsigned int printLevel, Boolean bDetailed)
{
	if ((value == NULL) ||
		((value->pvData == NULL) &&
		(value->type != IEC61850_DATATYPE_OCTET_STRING) &&
		(value->type != IEC61850_DATATYPE_VISIBLE_STRING) &&
		(value->type != IEC61850_DATATYPE_UNICODE_STRING))) {
		unsigned int i = 0;
		for (i = 0; i < printLevel; i++) { printf("  "); }
		printf("NULL\n");
	} else {
		unsigned int i = 0;
		PrintDataType((unsigned int)value->type, value->bitLength, printLevel);
		for (i = 0; i < printLevel; i++) { printf("  "); }
		printf("value: ");
		switch (value->type) {
		case IEC61850_DATATYPE_ERROR:
		{
			printf("%u [%s]", *((U32*)(value->pvData)), TranslateServiceError(*((eServiceError*)value->pvData)));
			break;
		}
		case IEC61850_DATATYPE_BOOLEAN:
		{
			if (value->bitLength == IEC61850_BOOLEAN_BITSIZE) {
				if (*((unsigned char*)value->pvData) == 0) {
					printf("FALSE");
				} else {
					printf("TRUE");
				}
			} else {
				printf("INVALID SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_INT8:
		{
			if ((value->bitLength == 8) && value->pvData) {
				printf("%hhi", *((S8*)(value->pvData)));
			} else {
				printf("INVALID SIZE");
			}
		}
		break;
		case IEC61850_DATATYPE_INT16:
		{
			if (value->bitLength == 8) {
				printf("%hhi", *((S8*)(value->pvData)));
			} else if (value->bitLength == 16) {
				S16 i16TempValue = 0;
				memcpy(&i16TempValue, value->pvData, sizeof(i16TempValue));
				printf("%hi", i16TempValue);
			} else {
				printf("INVALD SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_INT32:
		{
			if (value->bitLength == 8) {
				printf("%hhi", *((S8*)(value->pvData)));
			} else if (value->bitLength == 16) {
				S16 i16TempValue = 0;
				memcpy(&i16TempValue, value->pvData, sizeof(i16TempValue));
				printf("%hi", i16TempValue);
			} else if (value->bitLength == 32) {
				S32 i32Data = 0;
				memcpy(&i32Data, value->pvData, sizeof(i32Data));

#if defined (__PARADIGM__)
				printf(" An integer of 32 bits: %li", i32Data);
#else
				printf("%i", i32Data);
#endif
			} else {
				printf("INVALID SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_INT64:
		{
			if (value->bitLength == 8) {
				printf("%hhi", *((S8*)(value->pvData)));
			} else if (value->bitLength == 16) {
				S16 i16TempValue = 0;
				memcpy(&i16TempValue, value->pvData, sizeof(i16TempValue));
				printf("%hi", i16TempValue);
			} else if (value->bitLength == 32) {
				S32 i32Data = 0;
				memcpy(&i32Data, value->pvData, sizeof(i32Data));

				printf("%i", i32Data);
			} else if (value->bitLength == 64) {
#ifndef __PARADIGM__
				S64 i64Data = 0;
				memcpy(&i64Data, value->pvData, sizeof(i64Data));

				printf("%lld", (long long)i64Data);
#else
				S32 i64Data = 0; /* paradigm does not support 64 bit data so use 32 bit instead */
				memcpy(&i64Data, value->pvData, sizeof(i64Data));

				printf("%ld", (long)i64Data);
#endif

			} else {
				printf("INVALID SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_INT8U:
		{
			if (value->bitLength == 8) {
				printf("%hhu", *((U8*)(value->pvData)));
			} else {
				printf("INVALID SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_INT16U:
		{
			if (value->bitLength == 8) {
				printf("%hhu", *((U8*)(value->pvData)));
			} else if (value->bitLength == 16) {
				U16 tempValue = 0;
				memcpy(&tempValue, value->pvData, sizeof(tempValue));
				printf("%hu", tempValue);
			} else {
				printf("INVALID SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_INT32U:
		{
			if (value->bitLength == 8) {
				printf("%hhu", *((U8*)(value->pvData)));
			} else if (value->bitLength == 16) {
				U16 tempValue = 0;
				memcpy(&tempValue, value->pvData, sizeof(tempValue));
				printf("%hu", tempValue);
			} else if (value->bitLength == 32) {
				U32 u32Data = 0;
				memcpy(&u32Data, value->pvData, sizeof(u32Data));

#if defined (__PARADIGM__)
				printf("%lu", u32Data);
#else
				printf("%u", u32Data);
#endif
			} else {
				printf("INVALID SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_FLOAT32:
		{
			if (value->bitLength == 32) {
#if defined (__PARADIGM__)
				if (value->bitLength > 0) {
					unsigned int index = 0;
					for (index = 0; index < value->bitLength / 8; index++) {
						printf("%02X", *((unsigned char*)value->pvData + index));
					}
				}
#else
				Float32 fData = 1;
				memcpy(&fData, value->pvData, sizeof(Float32));
				printf("%g", fData);
#endif
			} else {
				printf("INVALID SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_FLOAT64:
		{
			if (value->bitLength == 64) {
#if defined (__PARADIGM__)
				if (value->bitLength > 0) {
					unsigned int index = 0;
					for (index = 0; index < value->bitLength / 8; index++) {
						printf("%02X", *((unsigned char*)value->pvData + index));
					}
				}
#else
				double dData = 1;
				memcpy(&dData, value->pvData, sizeof(double));
				printf("%g", dData);
#endif
			} else {
				printf("INVALID SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_ENUMERATED:
		case IEC61850_DATATYPE_CODED_ENUM:
		{
			if (value->bitLength > 0) {
				unsigned int totalBits = value->bitLength;
				unsigned int totalBytes = ((value->bitLength) + 7) / 8;
				unsigned int bit = 0, byte = 0;
				unsigned int i = 0;
				for (bit = 0, byte = 0; (bit < totalBits) && (byte < totalBytes); byte++) {
					unsigned char currByte = *((unsigned char*)value->pvData + byte);
					unsigned int i = 0;
					for (i = 0; (i < 8) && (bit < totalBits); i++, bit++) {
						unsigned char bitMask = (0x80 >> i);
						Boolean bitTrue = (Boolean)(currByte & bitMask);
						printf("%d", bitTrue ? 1 : 0);
					}
				}
				printf(" (binary)");
			} else {
				printf("INVALID SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_OCTET_STRING:
		{
			if (value->bitLength == 0) {
				printf("NULL");
			} else if (value->bitLength > 7) {
				unsigned int index = 0;
				printf("0x");
				for (index = 0; index < value->bitLength / 8; index++) {
					printf("%02X", *((unsigned char*)value->pvData + index));
				}
				printf(" (%u Bytes long)", value->bitLength / 8);
			} else {
				printf("INVALID SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_VISIBLE_STRING:
		{
			if (value->bitLength == 0) {
				printf("\"\"");
			} else if (value->bitLength > 7) {
				printf("\"%.*s\"", value->bitLength / 8, ((char*)(value->pvData)));
			} else {
				printf("INVALID SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_UNICODE_STRING:
		{
			if (value->bitLength == 0) {
				printf("\"\"");
			} else if (value->bitLength > 7) {
				printf("\"%.*s\"", value->bitLength / 8, ((char*)(value->pvData)));
			} else {
				printf("INVALID SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_TIMESTAMP:
		{
			if (value->bitLength == IEC61850_TIMESTAMP_BITSIZE) {
				PrintTimeStamp(value->pvData);
			} else {
				printf("INVALID SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_QUALITY:
		{
			if (value->bitLength == IEC61850_QUALITY_BITSIZE) {
				PrintQuality(value->pvData, printLevel, bDetailed);
			} else {
				printf("INVALID SIZE");
			}
			break;
		}
		case IEC61850_DATATYPE_ARRAY:
		{
			unsigned int count = 0;
			printf("\n");
			for (count = 0; count < value->bitLength; count++) {
				IEC61850_DataAttributeData* arrayValue = (IEC61850_DataAttributeData*)value->pvData;
				unsigned int i = 0;
				for (i = 0; i < printLevel + 1; i++) { printf("  "); }
				printf("[%d]:\n", count + 1);
				PrintDataValue(arrayValue + count, printLevel + 2, bDetailed);
			}
			break;
		}
		case IEC61850_DATATYPE_STRUCTURE:
		{
			unsigned int index = 0;
			IEC61850_DataAttributeData* structValue = value->pvData;
			printf("\n");
			for (index = 0; index < value->bitLength; index++) {
				PrintDataValue(&structValue[index], printLevel + 1, bDetailed);
			}
			break;
		}
		}
		if ((value->type != IEC61850_DATATYPE_STRUCTURE) && (value->type != IEC61850_DATATYPE_ARRAY)) {
			printf("\n");
			if ((value->type != IEC61850_DATATYPE_TIMESTAMP) && (value->type != IEC61850_DATATYPE_QUALITY)) {
				printf("\n");
			}
		}
	}
}

void PrintDataDefinition(DataDefinition* dataDefinition, unsigned int printLevel)
{
	unsigned int i = 0;
	if (dataDefinition->type == IEC61850_DATATYPE_STRUCTURE) {
		if (dataDefinition->structDefinition) {
			unsigned int iNextLevel = printLevel + 1;
			int j = 0;
			for (j = 0; j < dataDefinition->structSize; j++) {
				if (&(dataDefinition->structDefinition[j])) {
					for (i = 0; i < printLevel; i++) { printf("  "); }
					printf("name: [%s]\n", dataDefinition->structDefinition[j].name);
					for (i = 0; i < printLevel; i++) { printf("  "); }
					printf("fc:   [%s]\n", dataDefinition->structDefinition[j].FC);
					for (i = 0; i < printLevel; i++) { printf("  "); }
					printf("type: [%s]\n", TranslateDataType(dataDefinition->structDefinition[j].definition.type));
					PrintDataDefinition(&(dataDefinition->structDefinition[j].definition), iNextLevel);
				}
			}
		}
	} else if (dataDefinition->type == IEC61850_DATATYPE_ARRAY) {
		if (dataDefinition->arrayDefinition) {
			unsigned int iNextLevel = 0;
			for (i = 0; i < printLevel; i++) { printf("  "); }
			printf("numberOfElement: [%u]\n", dataDefinition->arraySize);
			for (i = 0; i < printLevel; i++) { printf("  "); }
			printf("elementType:     [%s]\n", TranslateDataType(dataDefinition->arrayDefinition->type));
			iNextLevel = printLevel + 1;
			PrintDataDefinition(dataDefinition->arrayDefinition, iNextLevel);
		}
	} else {
		printf("\n");
	}
}

void PrintGetServerDirectoryResponse(GetServerDirectory_Response* response)
{
	if (response) {
		if (response->serviceError == SERVICE_ERROR_NO_ERROR) {
			printf("Response+\n");
			printf("ServerDirectory List(ldname list):\n");
			if (response->reference) {
				PrintStringList(response->reference);
			}
			PrintMoreFollows(response->moreFollows);
		} else {
			printf("Response-\n\t");
			PrintServiceError(response->serviceError);
		}
	}
}

void PrintGetLogicalDeviceDirectoryResponse(GetLogicalDeviceDirectory_Response* response)
{
	if (response) {
		if (response->serviceError == SERVICE_ERROR_NO_ERROR) {
			printf("Response+\n");
			printf("LogicalDeviceDirectory List:\n");
			if (response->lnReference) {
				PrintStringList(response->lnReference);
			}
			PrintMoreFollows(response->moreFollows);
		} else {
			printf("Response-\n\t");
			PrintServiceError(response->serviceError);
		}
	}
}

void PrintGetLogicalNodeDirectoryResponse(GetLogicalNodeDirectory_Response* response)
{
	if (response) {
		if (response->serviceError == SERVICE_ERROR_NO_ERROR) {
			printf("Response+\n");
			printf("LogicalNodeDirectory List:\n");
			if (response->reference) {
				PrintStringList(response->reference);
			}
			PrintMoreFollows(response->moreFollows);
		} else {
			printf("Response-\n\t");
			printf("Service Error Code:%d\n", (int)response->serviceError);
		}
	}
}

void PrintGetAllDataValuesResponse(GetAllDataValues_Response* response)
{
	if (response) {
		if (response->serviceError == SERVICE_ERROR_NO_ERROR) {
			printf("Response+\n");
			PrintDataValue(&response->data, 1, FALSE);
			PrintMoreFollows(response->moreFollows);
		} else {
			printf("Response-\n\t");
			PrintServiceError(response->serviceError);
		}
	}
}

void PrintGetAllCBValuesResponse(GetAllCBValues_Response* response)
{
	if (response) {
		if (response->serviceError == SERVICE_ERROR_NO_ERROR) {
			printf("Response+\n");
			PrintAllCBValues(&response->cbValue);
			PrintMoreFollows(response->moreFollows);
		} else {
			printf("Response-\n\t");
			PrintServiceError(response->serviceError);
		}
	}
}

void PrintGetDataValuesResponse(GetDataValues_Response* response)
{
	if (response) {
		U32 i = 0;
		for (i = 0; i < response->dataNum; i++) {
			printf("data[%u]:\n", i + 1);
			PrintDataValue(&(response->dataAttributes[i]), 1, TRUE);
		}
	}
}

void PrintSetDataValuesResponse(SetDataValues_Response* response)
{
	if (response) {
		if (response->result.errNum > 0) {
			unsigned int i = 0;
			printf("Response-\n");
			for (i = 0; i < response->result.errNum; i++) {
				printf("\tresult[%u]: ", i + 1);
				PrintServiceError((eServiceError)(response->result.serviceErrs[i]));
			}
		} else {
			printf("Response+\n");
		}
	}
}

void PrintGetDataDirectoryResponse(GetDataDirectory_Response* response)
{
	if (response) {
		if (response->serviceError == SERVICE_ERROR_NO_ERROR) {
			printf("Response+\n");
			if (response->dataNum > 0) {
				unsigned int index = 0;
				printf("Data Directories: (%d)\n", response->dataNum);
				for (index = 0; index < response->dataNum; index++) {
					printf("dataAttribute[%u]:\n", index + 1);
					printf("  reference: [%s]\n  fc: [%s]\n\n", response->dataDirs[index].ref, response->dataDirs[index].FC);
				}
			}
			PrintMoreFollows(response->moreFollows);
		} else {
			printf("Response-\n\t");
			PrintServiceError(response->serviceError);
		}
	}
}

void PrintGetDataDefinitionResponse(GetDataDefinition_Response* response)
{
	if (response) {
		if (response->serviceError == SERVICE_ERROR_NO_ERROR) {
			printf("Response+\n");
			PrintDataDefinition(&response->dataRefDefinition->definition, FALSE);
		} else {
			printf("Response-\n\t");
			PrintServiceError(response->serviceError);
		}
	}
}

void PrintGetDataSetValuesResponse(GetDataSetValues_Response* response)
{
	if (response && response->dataNum > 0) {
		U32 i = 0;
		for (i = 0; i < response->dataNum; i++) {
			PrintDataValue(&(response->dataAttributes[i]), 1, TRUE);
		}
	}
}

void PrintSetDataSetValuesResponse(SetDataSetValues_Response* response)
{
	if (response) {
		if (response->result.errNum > 0) {
			unsigned int i = 0;
			printf("Response-\n");
			for (i = 0; i < response->result.errNum; i++) {
				printf("  result[%u]: ", i + 1);
				PrintServiceError((eServiceError)(response->result.serviceErrs[i]));
			}
		} else {
			printf("Response+\n");
		}
	}
}

void PrintGetBRCBValuesResponse(GetBRCBValues_Response* response)
{
	if (response) {
		if (response->serviceError == SERVICE_ERROR_NO_ERROR) {
			printf("GetBRCBValues success\n");

			PrintBRCBValues(&response->rcbVal);

		} else {
			printf("GetBRCBValues failed\n\t");
			PrintServiceError(response->serviceError);
		}
	}
}

void PrintSetBRCBValuesResponse(SetBRCBValues_Response* response)
{
	if (response) {
		if (response->serviceError == SERVICE_ERROR_NO_ERROR) {
			unsigned int cbIndex = 0;
			tSetBRCBErrors setRCBErrors = { 0 };
			printf("SetBRCBValues success\n");
			for (cbIndex = 0; cbIndex < response->numOfRptCB; cbIndex++) {
				if (memcmp(&response->setRCBErrsList[cbIndex], &setRCBErrors, sizeof(tSetBRCBErrors)) != 0) {
					printf("BRCB No.%u:\n", cbIndex + 1);
					if (response->setRCBErrsList[cbIndex].setRptIDError != SERVICE_ERROR_NO_ERROR) {
						printf("  rptID:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setRptIDError);
					}
					if (response->setRCBErrsList[cbIndex].setRptEnaError != SERVICE_ERROR_NO_ERROR) {
						printf("  rptEna:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setRptEnaError);
					}
					if (response->setRCBErrsList[cbIndex].setDataSetError != SERVICE_ERROR_NO_ERROR) {
						printf("  datSet:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setDataSetError);
					}
					if (response->setRCBErrsList[cbIndex].setOptFldsError != SERVICE_ERROR_NO_ERROR) {
						printf("  optFlds:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setOptFldsError);
					}
					if (response->setRCBErrsList[cbIndex].setBufTmError != SERVICE_ERROR_NO_ERROR) {
						printf("  bufTm:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setBufTmError);
					}
					if (response->setRCBErrsList[cbIndex].setTrgOpsError != SERVICE_ERROR_NO_ERROR) {
						printf("  trgOps:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setTrgOpsError);
					}
					if (response->setRCBErrsList[cbIndex].setIntgPdError != SERVICE_ERROR_NO_ERROR) {
						printf("  intgPd:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setIntgPdError);
					}
					if (response->setRCBErrsList[cbIndex].setGIError != SERVICE_ERROR_NO_ERROR) {
						printf("  gi:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setGIError);
					}
					if (response->setRCBErrsList[cbIndex].setPurgeBufError != SERVICE_ERROR_NO_ERROR) {
						printf("  purgeBuf:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setPurgeBufError);
					}
					if (response->setRCBErrsList[cbIndex].setEntryIDError != SERVICE_ERROR_NO_ERROR) {
						printf("  entryID:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setEntryIDError);
					}
					if (response->setRCBErrsList[cbIndex].setResvTmsError != SERVICE_ERROR_NO_ERROR) {
						printf("  resvTms:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setResvTmsError);
					}
				}
			}
		} else {
			printf("SetBRCBValues failed\n\t");
			PrintServiceError(response->serviceError);
		}
	}
}

void PrintGetURCBValuesResponse(GetURCBValues_Response* response)
{
	if (response) {
		if (response->serviceError == SERVICE_ERROR_NO_ERROR) {
			printf("GetURCBValues success\n");

			PrintURCBValues(&response->rcbVal);

		} else {
			printf("GetURCBValues failed\n\t");
			PrintServiceError(response->serviceError);
		}
	}
}

void PrintSetURCBValuesResponse(SetURCBValues_Response* response)
{
	if (response) {
		if (response->serviceError == SERVICE_ERROR_NO_ERROR) {
			unsigned int cbIndex = 0;
			tSetURCBErrors setRCBErrors = { 0 };
			printf("SetURCBValues success\n");
			for (cbIndex = 0; cbIndex < response->numOfRptCB; cbIndex++) {
				if (memcmp(&response->setRCBErrsList[cbIndex], &setRCBErrors, sizeof(tSetURCBErrors)) != 0) {
					printf("URCB No.%u:\n", cbIndex + 1);
					if (response->setRCBErrsList[cbIndex].setRptIDError != SERVICE_ERROR_NO_ERROR) {
						printf("  rptID:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setRptIDError);
					}
					if (response->setRCBErrsList[cbIndex].setRptEnaError != SERVICE_ERROR_NO_ERROR) {
						printf("  rptEna:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setRptEnaError);
					}
					if (response->setRCBErrsList[cbIndex].setDataSetError != SERVICE_ERROR_NO_ERROR) {
						printf("  datSet:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setDataSetError);
					}
					if (response->setRCBErrsList[cbIndex].setOptFldsError != SERVICE_ERROR_NO_ERROR) {
						printf("  optFlds:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setOptFldsError);
					}
					if (response->setRCBErrsList[cbIndex].setBufTmError != SERVICE_ERROR_NO_ERROR) {
						printf("  bufTm:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setBufTmError);
					}
					if (response->setRCBErrsList[cbIndex].setTrgOpsError != SERVICE_ERROR_NO_ERROR) {
						printf("  trgOps:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setTrgOpsError);
					}
					if (response->setRCBErrsList[cbIndex].setIntgPdError != SERVICE_ERROR_NO_ERROR) {
						printf("  intgPd:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setIntgPdError);
					}
					if (response->setRCBErrsList[cbIndex].setGIError != SERVICE_ERROR_NO_ERROR) {
						printf("  gi:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setGIError);
					}
					if (response->setRCBErrsList[cbIndex].setResvError != SERVICE_ERROR_NO_ERROR) {
						printf("  resv:\t");
						PrintServiceError(response->setRCBErrsList[cbIndex].setResvError);
					}
				}
			}
		} else {
			printf("SetURCBValues failed\n\t");
			PrintServiceError(response->serviceError);
		}
	}
}

char* TranslateServiceError(eServiceError error)
{
	switch (error) {
	case SERVICE_ERROR_NO_ERROR:
		return "no-error";
	case SERVICE_ERROR_INSTANCE_NOT_AVAILABLE:
		return "instance-not-available";
	case SERVICE_ERROR_INSTANCE_IN_USE:
		return "instance-in-use";
	case SERVICE_ERROR_ACCESS_VIOLATION:
		return "access-violation";
	case SERVICE_ERROR_ACCESS_NOT_ALLOWED_IN_CURRENT_STATE:
		return "access-not-allowed-in-current-state";
	case SERVICE_ERROR_PRARMETER_VALUE_INAPPROPRIATE:
		return "parameter-value-inappropriate";
	case SERVICE_ERROR_PARAMETER_VALUE_INCONSISTENT:
		return "parameter-value-inconsistent";
	case SERVICE_ERROR_CLASS_NOT_SUPPORTED:
		return "class-not-supported";
	case SERVICE_ERROR_INSTANCE_LOCKED_BY_OTHER_CLIENT:
		return "instance-locked-by-other-client";
	case SERVICE_ERROR_CONTROL_MUST_BE_SELECTED:
		return "control-must-be-selected";
	case SERVICE_ERROR_TYPE_CONFLICT:
		return "type-conflict";
	case SERVICE_ERROR_FAILED_DUE_TO_COMMUNICATIONS_CONSTRAINT:
		return "failed-due-to-communications-constraint";
	case SERVICE_ERROR_FAILED_DUE_TO_SERVER_CONSTRAIANT:
		return "failed-due-to-server-constraint";
	default:
		break;
	}
	return "";
}

char* TranslateSampleMode(SampleMode smpMod)
{
	switch (smpMod) {
	case SMP_MOD_SAMPLES_PER_NOMINAL_PERIOD:
		return "samples-per-nominal-period";
	case SMP_MOD_SAMPLES_PER_SECOND:
		return "samples-per-second";
	case SMP_MOD_SECONDS_PER_SAMPLE:
		return "seconds-per-sample";
	default:
		break;
	}
	return "";
}

char* TranslateDataType(IEC61850_DataType type)
{
	char* dataTypes[20] = { "ERROR","BOOLEAN","INT8","INT16","INT32","INT64","INT8U","INT16U",
		"INT32U","FLOAT32","FLOAT64","ENUMERATED","CODED_ENUM","OCTET_STRING","VISIBLE_STRING",
		"UNICODE_STRING","TIMESTAMP","QUALITY","ARRAY","STRUCTURE" };

	return dataTypes[type];
}